#if !defined(stdio)
#include <stdio.h>
#endif


//constants, defines and variables
const int STK_SZ = 10;
const int POISON = -666;

#define ASSERT_OK(type) if (!type##_OK(this_))  \
							{					\
							type##_dump(this_), \
							assert (!"not_OK -> the stack is bad"); \
							}

typedef double elem_t;


//creating stack
struct Stack_t
{
	int count;
	elem_t data[STK_SZ];
};


//prototypes of functions
void Stack_construct (Stack_t* st);
void Stack_destruct  (Stack_t* st);

int  Stack_OK   (const Stack_t* st);
void Stack_dump (const Stack_t* st);

int    Stack_push (Stack_t* this_, elem_t val);
elem_t Stack_pop  (Stack_t* this_            );


//functions themselves

				/*--------======== Main stack functions ========--------*/

void Stack_construct (Stack_t* st)
	{
	if (!st)
		{
		printf ("NULL pointer to the stack. The stack did not constructed.\n");
		return;
		}

	st -> count = 0;
	};


void Stack_destruct (Stack_t* st)
	{
	if (!st)
		{
		printf ("NULL pointer to the stack that is being destructed.\n");
		return;
		}

	st -> count = POISON;
	for (int i = 0; i < STK_SZ; i++)
		{
		st -> data[i] = POISON;
		}
	
	if (Stack_OK (st) == 0)
		printf ("The stack is successfully destructed.\n");
	else
		{
		printf ("The stack can not be destructed.\n");
		Stack_dump (st);
		}
	}


//if stack is OK function returns 1;
//if not                  returns 0;
int Stack_OK (const Stack_t* st)
	{
	return (st && 0 <= (st -> count) && (st -> count) <= STK_SZ);
	}


void Stack_dump (const Stack_t* st)
	{
	printf ("Dump of the stack:\n");
	if (Stack_OK (st) == 1)
		printf ("  the stack is OK;\n" );
	else
		printf ("  the stack is BAD;\n");
	printf ("  the address of the beginning of the stack: %x;\n", st);
	
	printf ("\t{\n"                                      );
	printf ("\tcount = %d\n",                 st -> count);
	printf ("\tSTK_SZ = %d\n\n",                   STK_SZ);

	for (int i = 0; i < STK_SZ; i++)
		{
		printf ("\tdata[%d] = %f ;",  i, st -> data[i] );
		
		if (i < (st -> count) )
			printf (              " *\n"               );
		else
			printf (              " ;\n"               );
		}
			
	printf("\t}\n"                                       );
	}


//if function ends correctly it returns 1;
//if not                        returns 0;
int Stack_push (Stack_t* this_, elem_t val)
	{
	ASSERT_OK(Stack);
	
	if ( (this_ -> count) + 1 > STK_SZ)
		return 0;

	(this_ -> data[this_ -> count]) = val;
	(this_ -> count) ++;

	ASSERT_OK(Stack);
	return 1;
	}


elem_t Stack_pop (Stack_t* this_)
	{
	elem_t pop_val = 0;
	ASSERT_OK(Stack);

	if ( (this_ -> count) < 1)
		{
		printf ("The stack is empty. You can not pop from an empty stack.\n");
		return POISON;
		}

	(this_ -> count) --;
	pop_val = (this_ -> data[this_ -> count]);
	this_ -> data[this_ -> count] = POISON;

	ASSERT_OK(Stack);
	return pop_val;
	}

				/*--------======== Arithmetic functions ========--------*/

//if function ends correctly it returns 1;
//if not                        returns 0;
int Stack_sum (Stack_t* this_)
	{
	ASSERT_OK(Stack);
	elem_t x = 0, y = 0;
	int assert_ver_val = 0;

	if ( (this_ -> count) < 2)
		return 0;

	x = Stack_pop (this_);
	y = Stack_pop (this_);

	assert_ver_val = Stack_push (this_, y + x);
	assert (assert_ver_val);

	ASSERT_OK(Stack);
	return 1;
	}


//if function ends correctly it returns 1;
//if not                        returns 0;
//**function subtracts the TOP placed number FROM the DEEPER (the first after the top) one
int Stack_sub (Stack_t* this_)
	{
	ASSERT_OK(Stack);
	elem_t x = 0, y = 0;
	int assert_ver_val = 0;

	if ( (this_ -> count) < 2)
		return 0;

	x = Stack_pop (this_);
	y = Stack_pop (this_);

	assert_ver_val = Stack_push (this_, y - x);
	assert (assert_ver_val);

	ASSERT_OK(Stack);
	return 1;
	}


//if function ends correctly it returns 1;
//if not                        returns 0;
int Stack_mul (Stack_t* this_)
	{
	ASSERT_OK(Stack);
	elem_t x = 0, y = 0;
	int assert_ver_val = 0;

	if ( (this_ -> count) < 2)
		return 0;

	x = Stack_pop (this_);
	y = Stack_pop (this_);

	assert_ver_val = Stack_push (this_, y * x);
	assert (assert_ver_val);

	ASSERT_OK(Stack);
	return 1;
	}


//if function ends correctly it returns 1;
//if not                        returns 0;
//**function divides the DEEPER (the first after the top) placed number BY the TOP one
int Stack_div (Stack_t* this_)
	{
	ASSERT_OK(Stack);
	elem_t x = 0, y = 0;
	int assert_ver_val = 0;

	if ( (this_ -> count) < 2)
		return 0;

	x = Stack_pop (this_);
	y = Stack_pop (this_);

	if (x == 0)
		return 0;

	assert_ver_val = Stack_push (this_, y / x);
	assert (assert_ver_val);

	ASSERT_OK(Stack);
	return 1;
	}
